home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
501-525
/
disk_518
/
post
/
post16s.lzh
/
postint.c
< prev
next >
Wrap
Text File
|
1991-04-17
|
60KB
|
2,120 lines
/* PostScript interpreter file "postint.c" - the basic interpreter */
/* (C) Adrian Aylward 1989, 1991 */
# include "post.h"
/* Initialise the interpreter */
void initint(int parms)
{ struct object token, *aptr;
int i;
/* Initialise the virtual machine */
vminit(parms);
/* Initialise the basic interpreter */
inest = 0;
istate.flags = 0;
istate.type = -1;
istate.vmbase = 0;
istate.gbase = 0;
istate.execbase = 0;
istate.pfcrec = NULL;
istack = vmallocv(sizeof (struct istate) * istacksize);
strncpy(prompt1, "> ", promptsize);
strncpy(prompt2, "- ", promptsize);
time(&time1);
random = 1;
nametable = vmallocv(sizeof (vmref) * nametablesize);
opernest = 0;
execnest = 0;
dictnest = 0;
operstack = vmallocv(sizeof (struct object) * operstacksize);
execstack = vmallocv(sizeof (struct object) * execstacksize);
dictstack = vmallocv(sizeof (struct object) * dictstacksize);
filetable = vmallocv(sizeof (struct file) * filetablesize);
filetable[0].ch = '\n';
filetable[0].open = openread;
filetable[0].fptr = sstdin;
filetable[1].ch = EOF;
filetable[1].open = openwrite;
filetable[1].fptr = sstdout;
filetable[2].ch = EOF;
filetable[2].open = openwrite;
filetable[2].fptr = sstderr;
optable = vmallocv(sizeof (struct operator) * (optablesize + 1));
opnum = 0;
/* Initialise the dictionaries */
dicttoken(&dictstack[0], systemdictsize);
systemname(&dictstack[0], "systemdict", 0);
dicttoken(&dictstack[1], userdictsize);
systemname(&dictstack[1], "userdict", 0);
dictnest = 2;
token.type = typestring;
token.flags = flagwprot;
token.length = strlen(version);
token.value.vref = vmalloc(token.length);
memcpy(vmsptr(token.value.vref), version, token.length);
systemname(&token, "version", 0);
token.type = typebool;
token.flags = 0;
token.length = 0;
token.value.ival = 0;
systemname(&token, "false", 0);
token.value.ival = 1;
systemname(&token, "true", 0);
token.type = typeint;
token.flags = 0;
token.length = 0;
token.value.ival = 1;
nametoken(&copies, "#copies", -1, 0);
dictput(dictstack[1].value.vref, &copies, &token);
/* Initialise the operators */
initop1();
initop2();
initop3();
initop4();
/* Initialise "errordict" */
dicttoken(&errordict, errordictsize);
systemname(&errordict, "errordict", 0);
token.type = typeoper;
token.flags = flagexec;
token.length = 0;
token.value.ival = 1;
for (i = 0; i <= errmax; i++)
{ nametoken(&errorname[i], errortable[i], -1, flagexec);
dictput(errordict.value.vref, &errorname[i], &token);
token.value.ival = 0;
}
/* The value of "handleerror" in "systemdict" is
* "errordict /handleerror get exec" */
token.type = typearray;
token.flags = flagexec;
token.length = 4;
token.value.vref = arrayalloc(4);
aptr = vmaptr(token.value.vref);
aptr[0] = errordict;
aptr[1] = errorname[0];
aptr[1].flags = 0;
nametoken(&aptr[2], "get", -1, flagexec);
nametoken(&aptr[3], "exec", -1, flagexec);
bind(&token, 0);
dictput(dictstack[0].value.vref, &errorname[0], &token);
/* Initialise "$error" */
dicttoken(&errdsdict, errdsdictsize);
nametoken(&token, "$error", -1, 0);
dictput(dictstack[0].value.vref, &token, &errdsdict);
token.type = typebool;
token.flags = 0;
token.length = 0;
token.value.ival = 0;
for (i = 0; i < edsmax; i++)
{ nametoken(&errdsname[i], errdstable[i], -1, flagexec);
errdstoken[i] = token;
dictput(errdsdict.value.vref, &errdsname[i], &token);
token.type = typenull;
}
/* Initialise the graphics state, character routines */
initgstate();
initchar();
}
/* Tidy up the interpreter */
void tidyint()
{ struct file *file;
int filenum;
/* Close all opened files */
if (filetable)
{ for (filenum = 3; filenum < filetablesize; filenum++)
{ file = &filetable[filenum];
if (file->open != 0) fclose(file->fptr);
}
filetable = (struct file *) 0;
}
/* Tidy up the virtual machine */
vmtidy();
}
/* Make a name and insert it into the system dictionary */
void systemname(struct object *token, char *sptr, int flags)
{ struct object nameobj;
nametoken(&nameobj, sptr, -1, flags);
dictput(dictstack[0].value.vref, &nameobj, token);
}
/* Make an operator and insert it into the system dictionary */
void systemop(void (*func)(), char *sptr)
{ struct object token;
if (opnum == optablesize) error(errlimitcheck);
optable[opnum].func = func;
optable[opnum].sptr = sptr;
token.type = typeoper;
token.flags = flagexec;
token.length = 0;
token.value.ival = opnum;
systemname(&token, sptr, flagexec);
opnum++;
}
/* The interpreter */
void interpret(struct object *interpreting)
{ struct object token, *executing, *savetoken;
/* Start with a null token, in case we get an error before we have read
* one. */
token.type = 0;
token.flags = 0;
token.value.ival = 0;
/* Push the object we want to execute onto the execution stack. Save the
* error jump buffer on the error stack. Set up the current token. */
if (execnest >= execstacksize) error(errexecstackoverflow);
execstack[execnest++] = *interpreting;
savetoken = currtoken;
while (setjmp(istate.errjmp) != 0) continue;
currtoken = &token;
/* Loop until the execution stack is empty. (I.e. the same level as it
* was when we entered. Check for interrupt. */
while (execnest != istate.execbase)
{ if (intsigflag != 0)
{ if (intsigflag == 1)
{ intsigflag = 0;
error(errinterrupt);
}
else
{ intsigflag = 0;
error(errkill);
}
}
executing = &execstack[execnest - 1];
/* If the top of the stack is executable extract the next token from
* it. */
if (executing->flags & flagexec)
{ if (executing->flags & flagxprot) error(errinvalidaccess);
if (executing->type == typearray)
{ if (executing->length == 0)
{ execnest--;
continue;
}
token = *vmaptr(executing->value.vref);
executing->value.vref += sizeof (struct object);
if (--executing->length == 0)
execnest--;
goto dir;
}
if (executing->type == typepacked)
{ if (executing->length == 0)
{ execnest--;
continue;
}
executing->value.vref +=
unpack(&token, vmsptr(executing->value.vref));
if (--executing->length == 0)
execnest--;
goto dir;
}
if (executing->type == typefile)
{ if (!scantoken(&token, executing, 0))
{ if (filetable[executing->length].emode != 0)
{ filetable[executing->length].emode = 0;
if (dictnest < 3) error(errdictstackunderflow);
dictnest--;
}
else
fileclose(executing);
execnest--;
continue;
}
goto dir;
}
if (executing->type == typestring)
{ if (!scantoken(&token, executing, 0))
{ execnest--;
continue;
}
goto dir;
}
}
/* Otherwise if it is a control operator execute it without popping
* the stack; for all other cases we pop it off the stack and
* execute it. */
token = *executing;
if (token.flags & flagctrl)
{ (*(optable[token.value.ival].func))();
continue;
}
execnest--;
/* Execute an object obtained indirectly. (Procedures are executed
* immediately.) */
ind: if (token.flags & flagexec)
{ if (token.type == typeoper)
{ (*(optable[token.value.ival].func))();
continue;
}
else if (token.type == typename)
{ if (dictfind(&token, &token) == -1) error(errundefined);
goto ind;
}
else
{ if (token.type == typenull) continue;
if (execnest == execstacksize) error(errexecstackoverflow);
execstack[execnest++] = token;
continue;
}
}
if (opernest == operstacksize) error(errstackoverflow);
operstack[opernest++] = token;
continue;
/* Execute an object obtained directly. (Procedures are pushed onto
* the operand stack.) */
dir: if (token.flags & flagexec)
{ if (token.type == typeoper)
{ (*(optable[token.value.ival].func))();
continue;
}
else if (token.type == typename)
{ if (dictfind(&token, &token) == -1) error(errundefined);
goto ind;
}
else if (token.type != typearray && token.type != typepacked)
{ if (token.type == typenull) continue;
if (execnest == execstacksize) error(errexecstackoverflow);
execstack[execnest++] = token;
continue;
}
}
if (opernest == operstacksize) error(errstackoverflow);
operstack[opernest++] = token;
}
/* Restore the current token and exit to the next outer level. */
currtoken = savetoken;
}
/* Push the interpreter stack before recursing */
void pushint(void)
{ if (inest == istacksize) error(errlimitcheck);
istack[inest++] = istate;
istate.flags = 0;
istate.type = -1;
istate.vmbase = vmnest;
istate.gbase = gnest;
istate.execbase = execnest;
istate.pfcrec = NULL;
}
/* Pop the interpreter (and vm and graphics) stacks after recursing */
void popint(void)
{ if (vmnest != istate.vmbase)
vmrest(istate.vmbase, -1);
if (gnest != istate.gbase)
{ gnest = istate.gbase + 1;
grest();
}
if (istate.pfcrec)
istate.pfcrec->count = 0;
istate = istack[--inest];
}
/* Put a character on an output stream */
void putch(FILE *fptr, int ch)
{ if (putc(ch, fptr) == EOF) error(errioerror);
}
/* Put a string on an output stream */
void putstr(FILE *fptr, char *str)
{ int ch;
while (ch = *str++)
if (putc(ch, fptr) == EOF) error(errioerror);
}
/* Put a memory buffer on an output stream */
void putmem(FILE *fptr, char *sptr, int length)
{ while (length--)
if (putc(*sptr++, fptr) == EOF) error(errioerror);
}
/* Put a memory buffer on an output stream, checking for funny characters */
void putcheck(FILE *fptr, char *sptr, int length)
{ int ch;
while (length--)
{ ch = *(unsigned char *)sptr++;
if (ch < 0x20 || ch >= 0x7f)
{ if (ch == '\n')
putstr(fptr, "\\n");
else if (ch == '\r')
putstr(fptr, "\\r");
else if (ch == '\t')
putstr(fptr, "\\t");
else if (ch == '\b')
putstr(fptr, "\\b");
else if (ch == '\f')
putstr(fptr, "\\f");
else
if (fprintf(fptr, "\\%03.3o", ch) == EOF) error(errioerror);
}
else
if (putc(ch, fptr) == EOF) error(errioerror);
}
}
/* Open a file */
void fileopen(struct object *token, int open, char *name, int length)
{ struct file *file;
int filenum;
if (length < 0) length = strlen(name);
if (length > namebufsize) error(errlimitcheck);
memcpy(namebuf, name, length);
namebuf[length] = 0;
if (strlen(namebuf) != length) error(errrangecheck);
if (strcmp(namebuf, "%stdin") == 0)
filenum = 0;
else if (strcmp(namebuf, "%stdout") == 0)
filenum = 1;
else if (strcmp(namebuf, "%stderr") == 0)
filenum = 2;
else
{ filenum = 3;
for (;;)
{ file = &filetable[filenum];
if (file->open == 0) break;
++filenum;
if (filenum == filetablesize) error(errlimitcheck);
}
}
if (filenum < 3)
{ file = &filetable[filenum];
if (file->fptr == NULL) error(errundefinedfilename);
if (file->open != (open & ~openfont)) error(errinvalidfileaccess);
}
else
{ file->fptr = fopen(namebuf, ((open == openwrite) ? "w" : "r"));
if (file->fptr == NULL) error(errundefinedfilename);
file->open = open & ~openfont;
file->saved = vmnest;
file->ch = EOF;
file->uflg = 0;
file->slen = 0;
file->emode = 0;
file->erand = 0;
file->stype = 0;
if (open & openfont) file->stype = -1;
}
token->type = typefile;
token->flags = 0;
token->length = filenum;
token->value.ival = file->generation;
}
/* Close a file */
void fileclose(struct object *token)
{ struct file *file;
FILE *fptr;
int open;
if (token->length > 2)
if (file = filecheck(token, (openread | openwrite)))
{ fptr = file->fptr;
open = file->open;
file->fptr = NULL;
file->generation++;
file->open = 0;
if (fclose(fptr) == EOF)
if (open & openwrite) error(errioerror);
}
}
/* Check a file is open */
struct file *filecheck(struct object *token, int open)
{ struct file *file;
file = &filetable[token->length];
if (file->generation == token->value.ival && (file->open & open) != 0)
return file;
else
return NULL;
}
/* Get the next character from a file, allowing IBM font format */
# define getf(file,fptr) (--file->slen >= 0 ? getc(fptr) : getfseg(file))
/* Unget the last character from a file, allowing IBM font format */
# define ungetf(ch,file,fptr) (file->slen++, ungetc(ch, fptr))
/* Locate the next segment of an IBM font format file */
int getfseg(struct file *file)
{ FILE *fptr;
int ch, i;
fptr = file->fptr;
file->slen = 0;
/* Unknown file type; assume IBM font if first character is 0x80 */
if (file->stype == -1)
{ ch = getc(fptr);
if (ch == EOF) error(errioerror);
ungetc(ch, fptr);
if (ch != 0x80) file->stype = 0;
}
/* Standard file; may come here after reading 2 Gigabytes? */
if (file->stype == 0)
{ file->slen = 0x7fffffff;
return getc(fptr);
}
/* IBM font format. Read 6 byte segment header */
gets:
ch = getc(fptr);
if (ch != 0x80)
{ if (ch != EOF || ferror(fptr)) error(errioerror);
return EOF;
}
ch = getc(fptr);
file->stype = ch;
if (ch == 1 || ch == 2)
{ file->stype = ch;
i = 4;
while (i--)
{ ch = getc(fptr);
if (ch == EOF) error(errioerror);
file->slen = (((unsigned) file->slen) >> 8) | (ch << 24);
}
}
else if (ch != 3)
error(errioerror);
if (--file->slen <= 0) goto gets;
return getc(fptr);
}
/* Initialise a file for decryption */
void fileeinit(struct object *token)
{ struct file *file;
FILE *fptr;
int digit[4], i, j, k, ch, dig, num;
file = filecheck(token, openread | openwrite);
if (file == NULL) error(errioerror);
fptr = file->fptr;
/* Skip white space characters, except for IBM binary sections */
ch = getf(file, fptr);
if (file->stype != 2)
while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
getf(file, fptr);
ungetf(ch, file, fptr);
/* Decrypt four binary bytes, checking whether they are all hex digits */
file->erand = einitexec;
file->emode = 2;
for (i = 0; i < 4; i++)
{ ch = getf(file, fptr);
if (ch == EOF)
{ if (ferror(fptr)) error(errioerror);
error(errsyntaxerror);
}
if ((digit[i] = digitval(ch)) >= 16) file->emode = 1;
file->erand = ((file->erand + ch) * ec1 + ec2) & emask;
}
/* If all hex, must be hex encryption. So decrypt four hex bytes */
if (file->emode == 2)
{ file->erand = einitexec;
j = 0;
for (k = 0; k < 4; k++)
{ if (j < i)
{ num = digit[j];
j++;
}
else
{ ch = getf(file, fptr);
if (ch == EOF && ferror(fptr)) error(errioerror);
if ((num = digitval(ch)) >= 16) error(errsyntaxerror);
}
if (j < i)
{ dig = digit[j];
j++;
}
else
{ ch = getf(file, fptr);
if (ch == EOF && ferror(fptr)) error(errioerror);
if ((dig = digitval(ch)) >= 16) error(errsyntaxerror);
}
ch = (num << 4) + dig;
file->erand = ((file->erand + ch) * ec1 + ec2) & emask;
}
}
}
/* Read a character from a file or string */
int readch(struct object *input, int depth)
{ struct file *file;
FILE *fptr;
int ch, cx, num, dig;
if (input->type == typefile)
{ file = &filetable[input->length];
if (file->uflg)
{ file->uflg = 0;
return file->ch;
}
fptr = file->fptr;
/* Not encrypted */
if (file->emode == 0)
{ if (file->ch == '\n' && fptr == sstdin && prompting)
{ if (intsigflag)
{ intsigflag = 0;
currtoken->type = 0;
currtoken->flags = 0;
currtoken->value.ival = 0;
error(errinterrupt);
}
if (depth >= 0)
fputs(((depth == 0) ? prompt1: prompt2), sstdout);
}
ch = getf(file, fptr);
if (ch == '\r' && depth != -2)
{ ch = getf(file, fptr);
if (ch != '\n')
{ ungetf(ch, file, fptr);
ch = '\n';
}
}
if (ch == EOF && ferror(fptr)) error(errioerror);
}
/* Encrypted */
else
{
/* Binary */
if (file->emode == 1)
{ cx = getf(file, fptr);
if (cx == EOF)
{ if (ferror(fptr)) error(errioerror);
error(errsyntaxerror);
}
}
/* Hex */
else if (file->emode == 2)
{ do ch = getf(file, fptr);
while (ch == ' ' || ch == '\t' ||
ch == '\r' || ch == '\n');
if ((num = digitval(ch)) >= 16)
{ if (ch == EOF && ferror(fptr)) error(errioerror);
error(errsyntaxerror);
}
do ch = getf(file, fptr);
while (ch == ' ' || ch == '\t' ||
ch == '\r' || ch == '\n');
if ((dig = digitval(ch)) >= 16)
{ if (ch == EOF && ferror(fptr)) error(errioerror);
error(errsyntaxerror);
}
cx = (num << 4) + dig;
}
/* End of encryption */
else
{ file->ch = EOF;
return EOF;
}
/* Decrypt */
ch = cx ^ (file->erand >> eshift);
file->erand = ((file->erand + cx) * ec1 + ec2) & emask;
if (ch == '\r' && depth != -2)
ch = '\n';
}
file->ch = ch;
return ch;
}
else
{ if (input->length == 0)
return EOF;
else
{ input->length--;
ch = *((unsigned char *) (vmsptr(input->value.vref)));
input->value.vref++;
return ch;
}
}
}
/* Unread a character from a file or string */
void unreadch(struct object *input, int ch)
{ if (input->type == typefile)
filetable[input->length].uflg = 1;
else
if (ch != EOF)
{ input->length++;
input->value.vref--;
}
}
/* If a character is a digit return its value */
int digitval(int ch)
{ if (ch >= '0' && ch <= '9') return ch - '0';
if (ch >= 'A' && ch <= 'Z') return ch - 'A' + 10;
if (ch >= 'a' && ch <= 'z') return ch - 'a' + 10;
return 99;
}
/* Scan a file or string for an object token */
int scantoken(struct object *token, struct object *input, int depth)
{ int ch, num, dig, length, nest, flags, load;
if (input->type == typefile)
if (filecheck(input, openread) == NULL) error(errioerror);
if (input->flags & flagxprot) error(errinvalidaccess);
lab:
ch = readch(input, depth);
switch (ch)
{ case EOF:
return 0;
case ' ': case '\t': case '\n':
goto lab;
case '%':
for (;;)
{ ch = readch(input, depth);
if (ch == EOF) return 0;
if (ch == '\n') goto lab;
}
case ')': case '>':
error(errsyntaxerror);
case '(':
length = 0;
nest = 1;
for (;;)
{ ch = readch(input, -1);
if (ch == EOF) error(errsyntaxerror);
if (ch == '(') nest++;
if (ch == ')' && --nest == 0) break;
if (ch == '\\')
{ ch = readch(input, -1);
if (ch == EOF) error(errsyntaxerror);
if (ch == '\n') continue;
if (ch == 'n') ch = '\n';
if (ch == 'r') ch = '\r';
if (ch == 't') ch = '\t';
if (ch == 'b') ch = '\b';
if (ch == 'f') ch = '\f';
num = digitval(ch);
if (num < 8)
{ ch = readch(input, -1);
dig = digitval(ch);
if (dig < 8)
{ num = num * 8 + dig;
ch = readch(input, -1);
dig = digitval(ch);
if (dig < 8)
num = num * 8 + dig;
else
unreadch(input, ch);
}
else
unreadch(input, ch);
ch = num;
}
}
*vmstring(length++, 1) = ch;
}
str: if (length > 65535) error(errlimitcheck);
token->type = typestring;
token->flags = 0;
token->length = length;
token->value.vref = vmalloc(length);
return 1;
case '<':
length = 0;
for (;;)
{ do
ch = readch(input, -1);
while (ch == ' ' || ch == '\t' || ch == '\n');
if ((num = digitval(ch)) >= 16)
{ if (ch == '>')
break;
else
error(errsyntaxerror);
}
do
ch = readch(input, -1);
while (ch == ' ' || ch == '\t' || ch == '\n');
if ((dig = digitval(ch)) >= 16)
{ if (ch == '>')
dig = 0;
else
error(errsyntaxerror);
}
*vmstring(length++, 1) = (num << 4) + dig;
if (ch == '>') break;
}
goto str;
case '{':
if (depth >= maxdepth) error(errlimitcheck);
nest = opernest;
for (;;)
{ ch = readch(input, depth);
if (ch == EOF) error(errsyntaxerror);
if (ch == ' ' || ch == '\t' || ch == '\n') continue;
if (ch == '%')
{ for (;;)
{ ch = readch(input, depth);
if (ch == EOF) error(errsyntaxerror);
if (ch == '\n') break;
}
continue;
}
if (ch == '}') break;
unreadch(input, ch);
if (opernest == operstacksize) error(errstackoverflow);
if (!scantoken(&operstack[opernest++], input, depth + 1))
error(errsyntaxerror);
}
token->length = length = opernest - nest;
if (packing)
{ token->type = typepacked;
token->flags = flagexec | flagwprot;
token->value.vref = arraypack(&operstack[nest], length);
}
else
{ token->type = typearray;
token->flags = flagexec;
token->value.vref = arrayalloc(length);
arraycopy(vmaptr(token->value.vref),
&operstack[nest], length);
}
opernest = nest;
return 1;
case '}':
error(errsyntaxerror);
case '[':
case ']':
namebuf[0] = ch;
nametoken(token, namebuf, 1, flagexec);
return 1;
default:
flags = flagexec;
load = 0;
if (ch == '/')
{ flags = 0;
ch = readch(input, depth);
if (ch == '/')
{ load = 1;
ch = readch(input, depth);
}
}
length = 0;
for (;;)
{ switch (ch)
{ case EOF:
case '%':
case '(': case ')': case '<': case '>':
case '[': case ']': case '{': case '}':
case '/':
unreadch(input, ch);
case ' ': case '\t': case '\n':
break;
default:
if (length == namebufsize) error(errlimitcheck);
namebuf[length++] = ch;
ch = readch(input, depth);
continue;
}
break;
}
namebuf[length] = ' ';
if (flags == flagexec)
if (numtoken(token, namebuf)) return 1;
nametoken(token, namebuf, length, flags);
if (load)
if (dictfind(token, token) == -1) error(errundefined);
return 1;
}
}
/* Make a number token if we can */
int numtoken(struct object *token, char *string)
{ char *sptr = string;
int ch, dig, num;
unsigned int base, limit;
int sign = 0, ovf = 0, digits = 0;
limit = 0x7fffffff;
ch = *sptr++;
if (ch == '+')
{ sign = 1;
ch = *sptr++;
}
else if (ch == '-')
{ sign = 2;
ch = *sptr++;
limit = 0x80000000;
}
if (ch == '.') goto decn;
num = digitval(ch);
if (num >= 10) return 0;
digits = 1;
for (;;)
{ ch = *sptr++;
dig = digitval(ch);
if (dig >= 10) break;
if (num > limit/10 - 1)
if ((dig > limit%10) || (num > limit/10)) ovf = 1;
num = num * 10 + dig;
}
if (ch != '#') goto decn;
ch = *sptr++;
if (sign != 0 || num == 0 || num > 36) return 0;
limit = 0xffffffff;
base = num;
num = digitval(ch);
if (num >= base) return 0;
for (;;)
{ ch = *sptr++;
dig = digitval(ch);
if (dig >= base) break;
if (num > limit/base - 1)
if ((dig > limit%base) || (num > limit/base)) ovf = 1;
num = num * base + dig;
}
if (ch != ' ') return 0;
if (ovf == 0) goto numi;
error(errlimitcheck);
decn:
if (ch == '.')
{ ovf = 1;
for (;;)
{ ch = *sptr++;
dig = digitval(ch);
if (dig >= 10) break;
digits = 1;
}
}
if (digits == 0) return 0;
if (ch == 'E' || ch == 'e')
{ ovf = 1;
digits = 0;
ch = *sptr++;
if (ch == '+' || ch == '-') ch = *sptr++;
for (;;)
{ dig = digitval(ch);
if (dig >= 10) break;
digits = 1;
ch = *sptr++;
}
if (digits == 0) return 0;
}
if (ch != ' ') return 0;
if (ovf == 0) goto numi;
token->type = typereal;
token->flags = 0;
token->length = 0;
token->value.rval = (double) atof(string);
return 1;
numi:
token->type = typeint;
token->flags = 0;
token->length = 0;
token->value.ival = (sign == 2)? -num: num;
return 1;
}
/* Make a name token by looking up its string in the name table */
void nametoken(struct object *token, char *string, int length, int flags)
{ struct name *nameptr;
vmref *nameslot, nameref;
char *s;
unsigned int hash = 0;
if (length < 0) length = strlen(string);
s = string + length;
while (s != string) hash = hash * 12345 + *--s;
nameslot = &nametable[hash % nametablesize];
for (;;)
{ nameref = *nameslot;
if (nameref == 0) break;
nameptr = vmnptr(nameref);
if (nameptr->hash == hash &&
nameptr->length == length &&
memcmp(nameptr->string, string, length) == 0)
goto lab;
nameslot = &nameptr->chain;
}
nameref = vmalloc(sizeof (struct name) - 2 + length);
nameptr = vmnptr(nameref);
nameptr->chain = 0;
nameptr->hash = hash;
nameptr->length = length;
memcpy(nameptr->string, string, length);
*nameslot = nameref;
lab:
token->type = typename;
token->flags = flags;
token->length = 0;
token->value.vref = nameref;
}
/* Create a new dictionary token */
void dicttoken(struct object *token, int size)
{ struct dictionary *dict;
vmref dref;
int length, slots, p, i;
/* Table of primes. */
static int primes[] =
{ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
37, 41, 43, 47, 53, 59, 61, 67, 71, 73,
79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
239, 241, 251, 257
};
/* Choose the number of hash table slots. Make it an odd number about
* 1.25 times the dictionary size, with at least one unused slot (so
* the search always terminates). */
if (size < 0) error(errrangecheck);
slots = size + size/4 + 1 | 1;
/* Round the number up to the next prime. */
lab:
if (slots > 65535) error(errlimitcheck);
for (i = 0; p = primes[i], p * p <= slots ; i++)
if (slots % p == 0)
{ slots += 2;
goto lab;
}
/* Now create the dictionary. */
length = (sizeof (struct dictionary)) +
sizeof (struct dictentry) * (slots - 1);
dref = vmalloc(length);
dict = vmdptr(dref);
dict->type = typedict;
dict->flags = 0;
dict->slots = slots;
dict->size = size;
dict->full = 0;
dict->saved = vmnest;
dict->length = length;
token->type = typedict;
token->flags = 0;
token->length = 0;
token->value.vref = dref;
}
/* Put the value of a key into a dictionary */
void dictput(vmref dref, struct object *key, struct object *val)
{ struct dictionary *dict;
union dictkey lkey, ekey;
struct vmlist *vmlist;
vmref vmlref, *vmlslot;
unsigned int hash, slot;
dict = vmdptr(dref);
if (dict->flags & flagwprot) error(errinvalidaccess);
/* Convert strings to names */
if (key->type == typenull)
error(errtypecheck);
if (key->type == typestring)
nametoken(&lkey.keyobj, vmsptr(key->value.vref), key->length, 0);
else
{ lkey.keyobj = *key;
lkey.keyobj.flags = 0;
}
/* If we have not saved the dictionary since the last vm save, we must
* save it now. */
if (dict->saved < vmnest)
{ vmlslot = &(vmstack[vmnest].hlist[vmhashsize]);
vmlref = vmalloc(sizeof (struct vmlist) + dict->length);
vmlist = vmvptr(vmlref);
vmlist->chain = *vmlslot;
vmlist->vref = dref;
vmlist->length = dict->length;
memcpy((char *) (vmlist + 1), (char *) dict, dict->length);
*vmlslot = vmlref;
dict->saved = vmnest;
}
/* Compute the hash value. If we need to rehash we add the hash value
* modulo the table size. Since the size is a prime number this will
* scan the entire table - unless the hash value is zero when we add
* one instead. */
slot = (lkey.keyint[0] * 2 + lkey.keyint[1]) % dict->slots;
hash = slot;
if (hash == 0) hash = 1;
/* Search the table for the key, or an empty slot. Then insert. */
for (;;)
{ ekey.keyobj = dict->entries[slot].key;
if (ekey.keyobj.type == 0)
{ if (dict->full == dict->size) error(errdictfull);
dict->full++;
dict->entries[slot].key = *key;
break;
}
ekey.keyobj.flags = 0;
if (ekey.keyint[1] == lkey.keyint[1] &&
ekey.keyint[0] == lkey.keyint[0])
{ dict->entries[slot].key.flags = key->flags;
break;
}
slot += hash;
if (slot >= dict->slots) slot -= dict->slots;
}
dict->entries[slot].val = *val;
}
/* Get the value of a key from a dictionary */
int dictget(vmref dref, struct object *key, struct object *val, int flags)
{ struct dictionary *dict;
union dictkey lkey, ekey;
unsigned int hash, slot;
dict = vmdptr(dref);
if (dict->flags & flags) error(errinvalidaccess);
/* Convert strings to names */
if (key->type == typenull)
error(errtypecheck);
if (key->type == typestring)
nametoken(&lkey.keyobj, vmsptr(key->value.vref), key->length, 0);
else
{ lkey.keyobj = *key;
lkey.keyobj.flags = 0;
}
/* Compute the hash value. */
slot = (lkey.keyint[0] * 2 + lkey.keyint[1]) % dict->slots;
hash = slot;
if (hash == 0) hash = 1;
/* Search the table. */
for (;;)
{ ekey.keyobj = dict->entries[slot].key;
if (ekey.keyobj.type == 0)
return 0;
ekey.keyobj.flags = 0;
if (ekey.keyint[1] == lkey.keyint[1] &&
ekey.keyint[0] == lkey.keyint[0])
{ *val = dict->entries[slot].val;
return 1;
}
slot += hash;
if (slot >= dict->slots) slot -= dict->slots;
}
}
/* Find a key in the dictionary stack */
int dictfind(struct object *key, struct object *val)
{ struct dictionary *dict;
union dictkey lkey, ekey;
unsigned int hash, slot;
int nest = dictnest;
/* Convert strings to names */
if (key->type == typenull)
error(errtypecheck);
if (key->type == typestring)
nametoken(&lkey.keyobj, vmsptr(key->value.vref), key->length, 0);
else
{ lkey.keyobj = *key;
lkey.keyobj.flags = 0;
}
/* Search all the directories on the stack. */
while (nest--)
{ dict = vmdptr(dictstack[nest].value.vref);
if (dict->flags & flagrprot) error(errinvalidaccess);
slot = (lkey.keyint[0] * 2 + lkey.keyint[1]) % dict->slots;
hash = slot;
if (hash == 0) hash = 1;
for (;;)
{ ekey.keyobj = dict->entries[slot].key;
if (ekey.keyobj.type == 0)
break;
ekey.keyobj.flags = 0;
if (ekey.keyint[1] == lkey.keyint[1] &&
ekey.keyint[0] == lkey.keyint[0])
{ *val = dict->entries[slot].val;
return nest;
}
slot += hash;
if (slot >= dict->slots) slot -= dict->slots;
}
}
return -1;
}
/* Pack an array */
vmref arraypack(struct object *aptr, int length)
{ char *sptr;
int len = 0;
while (length--)
{ sptr = vmstring(len, sizeof (struct object));
len += pack(aptr++, sptr);
}
return vmalloc(len);
}
/* Unpack an array */
void arrayunpk(struct object *aptr, char *sptr, int length)
{ while (length--) sptr += unpack(aptr++, sptr);
}
/* Pack the next element of an array */
int pack(struct object *token, char *sptr)
{ int type = token->type;
int flags = token->flags;
sptr[0] = type | flags;
switch (type)
{ case typenull:
case typemark:
return 1;
case typesave:
case typefile:
sptr[1] = token->length;
memcpy(sptr + 2, (char *) &token->value, sizeof token->value);
return 2 + sizeof token->value;
case typeoper:
case typebool:
sptr[1] = token->value.ival;
return 2;
case typeint:
if (token->value.ival >= -32 && token->value.ival < 224)
{ sptr[0] = typechar | flags;
sptr[1] = token->value.ival + 32;
return 2;
}
case typefont:
case typereal:
case typename:
case typedict:
case typeoper2:
memcpy(sptr + 1, (char *) &token->value, sizeof token->value);
return 1 + sizeof token->value;
case typearray:
case typepacked:
case typestring:
memcpy(sptr + 1, (char *) &token->length,
sizeof token->length + sizeof token->value);
return 1 + sizeof token->length + sizeof token->value;
}
}
/* Unpack the next element of an array */
int unpack(struct object *token, char *sptr)
{ int type = ((unsigned char *) sptr)[0];
token->flags = type & 0xf0;
token->type = type = type & 0x0f;
switch (type)
{ case typenull:
case typemark:
token->length = 0;
token->value.ival = 0;
return 1;
case typesave:
case typefile:
token->length = ((unsigned char *) sptr)[1];
memcpy((char *) &token->value, sptr + 2, sizeof token->value);
return 2 + sizeof token->value;
case typeoper:
case typebool:
token->length = 0;
token->value.ival = ((unsigned char *) sptr)[1];
return 2;
case typeoper2:
token->type = typeoper;
case typeint:
case typefont:
case typereal:
case typename:
case typedict:
token->length = 0;
memcpy((char *) &token->value, sptr + 1, sizeof token->value);
return 1 + sizeof token->value;
case typearray:
case typepacked:
case typestring:
memcpy((char *) &token->length, sptr + 1,
sizeof token->length + sizeof token->value);
return 1 + sizeof token->length + sizeof token->value;
case typechar:
token->type = typeint;
token->length = 0;
token->value.ival = ((unsigned char *) sptr)[1] - 32;
return 2;
}
}
/* Initialise the virtual machine */
void vminit(int parms)
{ vmnest = 0;
vmsegno = vmparms = parms;
vmsegsize = memvmin;
if (vmsegsize > 0x1000000) vmsegsize = 0x1000000;
vmused = 0;
vmhwm = 0;
vmmax = vmsegsize * (vmsegmax - vmparms);
memset((char *) &vmbeg, 0, sizeof vmbeg);
memset((char *) &vmnext, 0, sizeof vmnext);
memset((char *) &vmsize, 0, sizeof vmsize);
memset((char *) vmstack, 0, sizeof vmstack);
packing = 0;
}
/* Tidy up the virtual machine */
void vmtidy(void)
{ while (vmsegno >= vmparms)
{ memfree(vmbeg[vmsegno], vmsize[vmsegno]);
vmsegno--;
}
}
/* Set up a virtual machine parameter segment */
void vmparm(int parm, void *beg, int size)
{ vmbeg[parm] = beg;
vmsize[parm] = vmnext[parm] = size;
}
/* Allocate some memory in the virtual machine */
vmref vmalloc(int size)
{ vmref vref;
int blksize = (size + (mcalign - 1)) & ~(mcalign - 1);
if (blksize > vmsize[vmsegno] - vmnext[vmsegno])
vmallocseg(blksize, 0);
vref = vmxref(vmsegno, vmnext[vmsegno]);
vmnext[vmsegno] += blksize;
vmused += blksize;
if (vmused > vmhwm) vmhwm = vmused;
return vref;
}
/* Allocate some memory in the virtual machine */
void *vmallocv(int size)
{ vmref vref = vmalloc(size);
return vmvptr(vref);
}
/* Convert a virtual machine reference to an address */
void *vmxptr(vmref vref)
{ return vmvptr(vref);
}
/* Preallocate space for a string at the end of the virtual machine memory */
char *vmstring(int length, int size)
{ int blksize = length + size;
if (blksize > vmsize[vmsegno] - vmnext[vmsegno])
vmallocseg(blksize, length);
return vmbeg[vmsegno] + vmnext[vmsegno] + length;
}
/* Allocate a new virtual machine memory segment */
void vmallocseg(int blksize, int length)
{ char *vbeg;
int segsize, numsegs;
numsegs = (blksize + vmsegsize - 1) / vmsegsize;
segsize = vmsegsize * numsegs;
if (vmsegno + numsegs >
vmsegmax + (vmnext[vmsegno] == 0 ? 1 : 0)) error(errVMerror);
vbeg = memalloc(segsize);
if (vbeg == NULL) error(errmemoryallocation);
memcpy(vbeg, vmbeg[vmsegno] + vmnext[vmsegno], length);
if (vmnext[vmsegno] == 0)
{ memfree(vmbeg[vmsegno], vmsize[vmsegno]);
vmsegno--;
}
else
vmused += vmsize[vmsegno] - vmnext[vmsegno];
while (numsegs--)
{ vmsegno++;
if (numsegs == 0)
{ vmbeg[vmsegno] = vbeg;
vmsize[vmsegno] = segsize;
}
else
{ vmbeg[vmsegno] = NULL;
vmsize[vmsegno] = 0;
}
vmnext[vmsegno] = 0;
}
}
/* Save some virtual machine memory before updating it */
void vmsavemem(vmref vref, int length)
{ struct vmframe *vmframe;
struct vmlist *vmlist;
vmref vmlref, *vmlslot;
unsigned int hash;
vmframe = &vmstack[vmnest];
/* We don't need to save it if it is more recent than the last save */
if (vmscheck(vmframe, vref)) return;
/* Compute the hash value */
hash = vref % vmhashsize;
/* Look on the hash chain to see if we have saved it already */
vmlslot = &(vmframe->hlist[hash]);
vmlref = *vmlslot;
while (vmlref)
{ vmlist = vmvptr(vmlref);
if (vmlist->vref == vref && vmlist->length >= length)
return;
vmlref = vmlist->chain;
}
/* If we cannot find it save a copy and add it to the list */
vmlref = vmalloc(sizeof (struct vmlist) + length);
vmlist = vmvptr(vmlref);
vmlist->chain = *vmlslot;
vmlist->vref = vref;
vmlist->length = length;
memcpy((char *) (vmlist + 1), vmsptr(vref), length);
*vmlslot = vmlref;
}
/* Save the virtual machine */
void vmsave(struct object *token)
{ struct vmframe *vmframe;
if (istate.flags & intgraph) error(errundefined);
if (vmnest == vmstacksize || gnest == gstacksize) error(errlimitcheck);
gsave();
vmframe = &vmstack[vmnest];
token->type = typesave;
token->flags = 0;
token->length = vmnest;
token->value.ival = vmframe->generation;
vmnest++;
vmframe++;
vmframe->generation++;
vmframe->gnest = gnest;
vmframe->packing = packing;
vmframe->vsegno = vmsegno;
vmframe->vnext = vmnext[vmsegno];
vmframe->vused = vmused;
memset((char *)vmframe->hlist, 0, sizeof vmframe->hlist);
}
/* Restore the virtual machine */
void vmrest(int nest, int generation)
{ struct vmframe *vmframe;
int vsegno, vnext, vused;
if (istate.flags & intgraph) error(errundefined);
if (nest < istate.vmbase ||
nest >= vmnest ||
(generation != -1 && generation != vmstack[nest].generation))
error(errinvalidrestore);
vmframe = &vmstack[nest + 1];
/* Check the stacks */
vmrestcheck(vmframe, operstack, opernest);
vmrestcheck(vmframe, execstack, execnest);
vmrestcheck(vmframe, dictstack, dictnest);
gnest = vmframe->gnest;
packing = vmframe->packing;
vsegno = vmframe->vsegno;
vnext = vmframe->vnext;
vused = vmframe->vused;
/* Restore file and name tables, the font cache, and the memory */
vmrestfiles(nest);
vmrestnames(vmframe);
vmrestfont(vmframe);
vmrestmem(nest);
/* Clear the memory we have freed */
memset(vmbeg[vsegno] + vnext, 0, vmnext[vsegno] - vnext);
while (vmsegno > vsegno)
{ memfree(vmbeg[vmsegno], vmsize[vmsegno]);
vmsegno--;
}
vmnext[vmsegno] = vnext;
vmused = vused;
/* Restore the graphics state */
grest();
}
/* Check a stack for objects refering to memory we are recovering */
void vmrestcheck(struct vmframe *vmframe,
struct object *stackptr, int stackcnt)
{ while (stackcnt--)
{ if (stackptr->type == typestring ||
stackptr->type == typearray ||
stackptr->type == typepacked ||
stackptr->type == typedict)
if (vmscheck(vmframe, stackptr->value.vref))
error(errinvalidrestore);
stackptr++;
}
}
/* Restore the file table */
void vmrestfiles(int nest)
{ struct file *file = &filetable[3];
int num = 3;
while (num < filetablesize)
{ if (file->open != 0 && file->saved > nest)
{ fclose(file->fptr);
file->fptr = NULL;
file->generation++;
file->open = 0;
}
file++;
num++;
}
}
/* Restore the name table */
void vmrestnames(struct vmframe *vmframe)
{ vmref *nslot1, *nslot2, nref;
int i;
nslot1 = &nametable[0];
i = nametablesize;
/* Scan each hash chain. Unlink all the names more recent than the
* save (the tail of the chain). */
while (i--)
{ nslot2 = nslot1;
for (;;)
{ nref = *nslot2;
if (nref == 0)
break;
if (vmscheck(vmframe, nref))
{ *nslot2 = 0;
break;
}
nslot2 = &(vmnptr(nref)->chain);
}
nslot1++;
}
}
/* Restore the saved memory */
void vmrestmem(int nest)
{ struct vmframe *vmframe;
struct vmlist *vmlist;
vmref vmlref, *vmlslot;
int i;
vmframe = &vmstack[vmnest];
do
{ vmlslot = &(vmframe->hlist[0]);
i = vmhashsize + 1;
while (i--)
{ vmlref = *vmlslot++;
while (vmlref)
{ vmlist = vmvptr(vmlref);
memcpy(vmsptr(vmlist->vref),
(char *)(vmlist + 1), vmlist->length);
vmlref = vmlist->chain;
}
}
vmframe--;
vmnest--;
} while (vmnest > nest);
}
/* Convert an object to a string */
int cvstring(struct object *token, char *sptr, int length)
{ struct name *nptr;
char *buf;
int len;
switch (token->type)
{ case typeint:
buf = namebuf;
len = sprintf(buf, "%d", token->value.ival);
break;
case typereal:
buf = namebuf;
len = sprintf(buf, "%g", token->value.rval);
if (strchr(buf, '.') == NULL) buf[len++] = '.';
break;
case typebool:
if (token->value.ival)
buf = "true";
else
buf = "false";
goto str;
case typestring:
if (token->flags & flagrprot) error(errinvalidaccess);
len = token->length;
buf = vmsptr(token->value.vref);
break;
case typename:
nptr = vmnptr(token->value.vref);
len = nptr->length;
buf = nptr->string;
break;
case typeoper:
buf = optable[token->value.ival].sptr;
goto str;
default:
buf = "--nostringval--";
str: len = strlen(buf);
}
if (len > length) error(errrangecheck);
if (sptr != buf) memcpy(sptr, buf, len);
return len;
}
/* Print an object in "=" style */
void printequals(FILE *fptr, struct object *token)
{ char *sptr;
int length;
if (token->type == typestring)
{ if (token->flags & flagrprot)
{ putstr(fptr, "--nostringval--");
return;
}
length = token->length;
sptr = vmsptr(token->value.vref);
}
else
length = cvstring(token, sptr = namebuf, namebufsize);
putmem(fptr, sptr, length);
}
/* Print an object in "==" style */
void printeqeq(FILE *fptr, struct object *token, int depth, int count)
{ struct object upelem, *element;
char *sptr;
int length;
if (count != 0) putch(fptr, ' ');
switch (token->type)
{ case typenull:
case typemark:
case typesave:
case typefile:
case typedict:
case typefont:
type: putch(fptr, '-');
putstr(fptr, typetable[token->type]);
putch(fptr, '-');
break;
case typeoper:
putstr(fptr, "--");
putstr(fptr, optable[token->value.ival].sptr);
putstr(fptr, "--");
break;
case typearray:
if (!(token->flags & flagrprot) && depth < maxdepth)
{ putch(fptr, (token->flags & flagexec) ? '{' : '[');
length = token->length;
element = vmaptr(token->value.vref);
while (length--)
printeqeq(fptr, element++, depth+1, ++count);
putch(fptr, ' ');
putch(fptr, (token->flags & flagexec) ? '}' : ']');
break;
}
goto type;
case typepacked:
if (!(token->flags & flagrprot) && depth < maxdepth)
{ putch(fptr, (token->flags & flagexec) ? '{' : '[');
length = token->length;
sptr = vmsptr(token->value.vref);
while (length--)
{ sptr += unpack(&upelem, sptr);
printeqeq(fptr, &upelem, depth+1, ++count);
}
putch(fptr, ' ');
putch(fptr, (token->flags & flagexec) ? '}' : ']');
break;
}
goto type;
case typestring:
if (!(token->flags & flagrprot))
{ putch(fptr, '(');
putcheck(fptr, vmsptr(token->value.vref), token->length);
putch(fptr, ')');
break;
}
goto type;
case typename:
if (!(token->flags & flagexec)) putch(fptr, '/');
default:
length = cvstring(token, namebuf, namebufsize);
putcheck(fptr, namebuf, length);
break;
}
}
/* Test two objects for equality */
int equal(struct object *token1, struct object *token2)
{ struct object tokn1 = *token1, tokn2 = *token2;
struct name *nptr;
char *buf1, *buf2;
if (tokn1.type == typeint && tokn2.type == typeint)
return tokn1.value.ival == tokn2.value.ival;
if (tokn1.type == typeint)
{ tokn1.type = typereal;
tokn1.value.rval = tokn1.value.ival;
}
if (tokn2.type == typeint)
{ tokn2.type = typereal;
tokn2.value.rval = tokn2.value.ival;
}
if (tokn1.type == typereal && tokn2.type == typereal)
return tokn1.value.rval == tokn2.value.rval;
if ((tokn1.flags & flagrprot) || (tokn2.flags & flagrprot))
error(errinvalidaccess);
if (tokn1.type == typestring)
buf1 = vmsptr(tokn1.value.vref);
if (tokn2.type == typestring)
buf2 = vmsptr(tokn2.value.vref);
if (tokn1.type == typename)
{ nptr = vmnptr(tokn1.value.vref);
tokn1.type = typestring;
tokn1.length = nptr->length;
buf1 = &nptr->string[0];
}
if (tokn2.type == typename)
{ nptr = vmnptr(tokn2.value.vref);
tokn2.type = typestring;
tokn2.length = nptr->length;
buf2 = &nptr->string[0];
}
if (tokn1.type == typestring && tokn2.type == typestring)
{ if (tokn1.length != tokn2.length) return 0;
return (memcmp(buf1, buf2, tokn1.length) == 0);
}
if (tokn1.type == tokn2.type &&
tokn1.length == tokn2.length &&
tokn1.value.ival == tokn2.value.ival)
return 1;
return 0;
}
/* Compare two objects */
int compare(struct object *token1, struct object *token2)
{ struct object tokn1 = *token1, tokn2 = *token2;
unsigned char *sptr1, *sptr2;
int length;
if (tokn1.type == typeint && tokn2.type == typeint)
{ if (tokn1.value.ival == tokn2.value.ival)
return 0;
else if (tokn1.value.ival < tokn2.value.ival)
return -1;
else
return 1;
}
if (tokn1.type == typeint)
{ tokn1.type = typereal;
tokn1.value.rval = tokn1.value.ival;
}
if (tokn2.type == typeint)
{ tokn2.type = typereal;
tokn2.value.rval = tokn2.value.ival;
}
if (tokn1.type == typereal && tokn2.type == typereal)
{ if (tokn1.value.rval == tokn2.value.rval)
return 0;
else if (tokn1.value.rval < tokn2.value.rval)
return -1;
else
return 1;
}
if (tokn1.type == typestring && tokn2.type == typestring)
{ if ((tokn1.flags & flagrprot) || (tokn2.flags & flagrprot))
error(errinvalidaccess);
length = (tokn1.length < tokn2.length) ?
tokn1.length : tokn2.length;
sptr1 = (unsigned char *) vmsptr(tokn1.value.vref);
sptr2 = (unsigned char *) vmsptr(tokn2.value.vref);
while (length--)
{ if (*sptr1 != *sptr2) return (*sptr1 - *sptr2);
sptr1++;
sptr2++;
}
return (tokn1.length - tokn2.length);
}
error(errtypecheck);
return 0;
}
/* Bind a procedure */
void bind(struct object *proc, int depth)
{ struct object token, *aptr;
char *sptr;
int length, len;
length = proc->length;
/* Array. If not write protected, save it and scan looking up executable
* names and replacing them if they are operators. Recurse for embedded
* procedures */
if (proc->type == typearray)
{ if (proc->flags & flagwprot) return;
aptr = vmaptr(proc->value.vref);
arraysave(proc->value.vref, length);
while (length--)
{ if (aptr->flags & flagexec)
if (aptr->type == typename)
{ if (dictfind(aptr, &token) != -1)
if (token.type == typeoper) *aptr = token;
}
else if (aptr->type == typearray || aptr->type == typepacked)
{ if (depth == maxdepth) error(errlimitcheck);
bind(aptr, depth + 1);
aptr->flags |= flagwprot;
}
aptr++;
}
}
/* Packed array. First unpack it to calculate the length to save. Then
* scan it unpacking sequentially. Replace names with oper2 (same size).
* Repack any elements we update */
else
{ sptr = vmsptr(proc->value.vref);
len = 0;
while (length--)
len += unpack(&token, sptr + len);
vmsavemem(proc->value.vref, len);
length = proc->length;
while (length--)
{ len = unpack(&token, sptr);
if (token.flags & flagexec)
if (token.type == typename)
{ if (dictfind(&token, &token) != -1)
if (token.type == typeoper)
{ token.type = typeoper2;
pack(&token, sptr);
}
}
else if (token.type == typearray || token.type == typepacked)
{ if (depth == maxdepth) error(errlimitcheck);
bind(&token, depth + 1);
token.flags |= flagwprot;
pack(&token, sptr);
}
sptr += len;
}
}
}
/* Estimate user (elapsed) time in milliseconds */
int usertime(void)
{ time(&time2);
return (time2 - time1) * 1000;
}
/* Stop */
void stop(void)
{ struct object token, *token1;
int nest = execnest;
token1 = &execstack[nest];
/* Search the execution stack for a "stopped". Long jump if we find
* one. Close "run" files as we go. */
while (nest)
{ token1--;
if (token1->flags & flagrun)
fileclose(token1 - 1);
else if (token1->flags & flagstop)
{ if (opernest == operstacksize) error(errstackoverflow);
token.type = typebool;
token.flags = 0;
token.length = 0;
token.value.ival = 1;
operstack[opernest++] = token;
execnest = nest - 2;
errorjmp(token1->length, 1);
}
nest--;
}
}
/* Error routine */
void error(int errnum)
{ struct object token;
int nest;
errornum = errnum;
errorstring = errortable[errornum];
/* Error during initialisation */
if (errorflag == 0)
nest = 0;
/* Error trapping enabled */
else
{ flushlevel(0);
/* Save the error name and command in memory */
errdstoken[edserrorname] = errorname[errnum];
errdstoken[edserrorname].flags = 0;
errdstoken[edscommand] = *currtoken;
/* If we are not already in the error handler, save the stacks too,
* and call it if we can (and not killed) */
if (errorflag == 2)
{ errorflag = 1;
errorarray(&token, operstack, opernest);
errdstoken[edsostack] = token;
errorarray(&token, execstack, execnest);
errdstoken[edsestack] = token;
errorarray(&token, dictstack, dictnest);
errdstoken[edsdstack] = token;
if (errnum != errkill)
{ if (execnest < execstacksize &&
dictget(errordict.value.vref, &errorname[errnum],
&token, 0))
{ execstack[execnest++] = token;
errorflag = 2;
}
}
}
/* Otherwise return to interactive or quit */
if (errorflag != 2)
{ errorflag = 2;
errorexit();
errormsg();
nest = 0;
}
else
nest = inest;
}
errorjmp(nest, 1);
}
/* Error save array, if there is enough memory */
void errorarray(struct object *token1, struct object *aptr, int length)
{ struct object token;
if (vmused + length * sizeof (struct object) <= vmmax)
{ token.type = typearray;
token.flags = 0;
token.length = length;
token.value.vref = arrayalloc(length);
arraycopy(vmaptr(token.value.vref), aptr, length);
}
else
{ token.type = typenull;
token.flags = 0;
token.length = 0;
token.value.ival = 0;
}
*token1 = token;
}
/* Error return to interactive mode or exit */
void errorexit(void)
{ struct file *file;
FILE *fptr;
if (prompting)
{ execnest = 1;
file = &filetable[0];
file->emode = 0;
fptr = file->fptr;
while (file->ch != EOF && file->ch != '\n')
file->ch = getf(file, fptr);
}
else
{ execnest = 0;
returncode = 10;
}
}
/* Print an error message */
void errormsg(void)
{ if (sstderr)
{ putstr(sstderr, "post: error: ");
printequals(sstderr, &errdstoken[edserrorname]);
putstr(sstderr, ", command ");
printeqeq(sstderr, &errdstoken[edscommand], 0, 0);
putch(sstderr, '\n');
}
}
/* Long jump to the error jump buffer */
void errorjmp(int nest, int num)
{ while (nest < inest)
{ if (istate.pfcrec)
istate.pfcrec->count = 0;
istate = istack[--inest];
}
longjmp(istate.errjmp, num);
}
/* End of file "postint.c" */